package com.lsh.oms.core.records;

import com.lsh.base.lang.DateTimes;
import com.lsh.base.lang.Exceptions;
import com.lsh.base.lang.Lists;
import com.lsh.base.lang.Maps;
import com.lsh.oms.core.exception.BusinessException;
import com.lsh.oms.core.model.order.OrderHead;
import com.lsh.oms.core.proxy.service.TmsProxy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import static com.lsh.base.lang.BigDecimals.*;
import static com.lsh.base.lang.bean.Beans.*;
import static com.lsh.oms.core.records.core.Return.Status.*;
import static java.math.BigDecimal.ZERO;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;

public class AfterSaleReturn extends ReturnRecord {

    private static final Logger LOGGER = LoggerFactory.getLogger(AfterSaleReturn.class);

    @Resource
    private TmsProxy tms;

    @Override
    public void start() {
        tasks.addHttpTrigger(id, venderId, Maps.newHashMap("method", "POST", "url", launchTarget(), "entity", Collections.emptyMap()));
    }

    @Override
    public void preDeliver(Map<String, Object> request) {
        LOGGER.info("return: {} pre deliver with request: {}", id, request);
        String routeId = getString(request, "route_id");
        change(Maps.newHashMap("route_id", routeId), $ -> $.status = PRE_DELIVER, PENDING);
        this.routeId = routeId;
    }

    @Override
    public void deliver(Map<String, Object> request) {
        LOGGER.info("return: {} deliver with request: {}", id, request);

        Map<Long, ReturnDetail> detailsGroupById = details.stream().collect(toMap($ -> $.id(), $ -> $));

        List<Map<String, Object>> detailsShouldDeliver = getList(request, "details", details.stream().map($ -> {
            Map<String, Object> result = new HashMap<>();
            result.put("id", $.id());
            result.put("quantity", $.quantity());
            return result;
        }).collect(toList()));

        ensureDeliverQuantityNotOver(detailsShouldDeliver, detailsGroupById);

        detailsShouldDeliver.forEach($ ->
                Optional.ofNullable(detailsGroupById.get(getLong($, "id")))
                        .ifPresent(forUpdate ->
                                forUpdate.updateActualQuantity(getBigDecimal($, "quantity", ZERO))));


        BigDecimal deliveredQuantity = mapper.findDetails(Lists.newArrayList(id)).stream().map($ -> $.actualQuantity()).reduce(ZERO, BigDecimal::add);

        Long deliverymanId = getLong(request, "deliveryman_id");
        if (greaterThanZero(deliveredQuantity)) {
            change(Maps.newHashMap("deliveryman_id", deliverymanId),
                    $ -> $.status = DELIVERED,
                    PRE_DELIVER);

            tasks.addHttpTrigger(id, venderId, Maps.newHashMap("method", "POST", "url", refundTarget(), "entity", Collections.emptyMap()));
        } else {
            change(Maps.newHashMap("deliveryman_id", deliverymanId),
                    $ -> $.status = TERMINATED,
                    PRE_DELIVER);
        }
        this.deliverymanId = deliverymanId;
    }

    private void ensureDeliverQuantityNotOver(List<Map<String, Object>> detailsShouldDeliver, Map<Long, ReturnDetail> detailsGroupById) {
        detailsShouldDeliver.forEach($ -> {
            Optional.ofNullable(detailsGroupById.get(getLong($, "id"))).ifPresent($$ -> {
                BigDecimal requested = getBigDecimal($, "quantity", ZERO);
                if (greaterThan(requested, $$.quantity())) {
                    throw BusinessException.badRequest("取货数量大于退货数量");
                }
            });
        });
    }

    @Override
    public void refund(Map<String, Object> request) {
        LOGGER.info("return: {} refund with request: {}", id, request);
        Map<String, Object> form = Maps.newHashMap("order_id", orderId, "type", 4, "relation_id", id);
        Map<String, Object> response = https.postFrom(misHost + "/refund/order/apply", Maps.newHashMap("venderId", venderId), form);
        Boolean success = getBoolean(response, "content.scalar", false);
        if (!success) {
            throw BusinessException.badRequest("退款失败");
        }
    }

    @Override
    public void run(Map<String, Object> request) {
        OrderHead order = orders.findById(orderId, false, false).orElseThrow(BusinessException::orderNotFound);
        List<Map<String, Object>> items = details.stream().map($ -> ((ReturnDetailRecord) $)).map($ -> {
            Map<String, Object> item = new HashMap<>();
            item.put("pack_unit", "");
            item.put("pack_name", "");
            item.put("is_weighing_goods", $.isWeighingGoods ? 1 : 0);
            item.put("sale_unit", $.saleUnit);
            BigDecimal qty = $.isWeighingGoods() ? $.actualQuantity() : multiplyWithScale4($.saleUnit, $.actualQuantity());
            item.put("s_qty", qty);
            item.put("item_qty", qty);
            item.put("item_supply_code", $.code);
            item.put("name", $.skuName);
            item.put("item_id", $.itemId);
            return item;
        }).collect(Collectors.toList());

        Map<String, Object> form = new HashMap<>();
        form.put("warehouse_id", warehouseId);
        form.put("other_id", id);
        form.put("type", 3);
        form.put("address_info", order.getAddressInfo());
        form.put("money", actualAmount());
        form.put("ordered_at", DateTimes.seconds(createdAt));
        form.put("source_system", Collections.emptyList());
        form.put("items", items);
        tms.createTask(form);
    }

    @Override
    public void cancel(Map<String, Object> request) {
        LOGGER.info("return: {} cancel with request: {}", id, request);
        try {
            tms.cancelTask(Maps.newHashMap("other_id", id, "type", 3));
        } catch (Exception e) {
            Exceptions.printStackTraceLineByLine(e);
        }

        details.forEach($ -> $.updateActualQuantity(ZERO));

        change($ -> $.status = CANCELED, PENDING, PRE_DELIVER);
    }
}
